package com.tsystems.school;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: victorn
 * Date: 8/14/11
 * Time: 1:16 AM
 * To change this template use File | Settings | File Templates.
 */
public class MyHashMap<K, V> implements Map<K, V> {

    final int DEFAULT_CAPACITY = 50;
    final int DEFAULT_TRESHOLD = 20;

    private int size;
    private int treshold;
    private int capacity;
    private Entity<K, V>[] entities;

    public MyHashMap() {
        size = 0;

        capacity = DEFAULT_CAPACITY;
        treshold = DEFAULT_TRESHOLD;

        entities = new Entity[capacity];

        //initAllEntities();
    }

    public MyHashMap(int capacity, int treshold) {
        if (capacity > 0)
            this.capacity = capacity;
        else
            this.capacity = DEFAULT_CAPACITY;

        if (treshold > 0)
            this.treshold = treshold;
        else
            this.treshold = DEFAULT_TRESHOLD;

        entities = new Entity[capacity];
        size = 0;
    }

    private int getHash(K key, int modulus) {

        //System.out.println("Key in getHash() = " + key);

        return Math.abs(key.hashCode() % modulus);
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean containsKey(Object key) {

        int hash = getHash((K) key, capacity);

        if (entities[hash] == null)
            return false;

        return entities[hash].containsKey((K) key);
    }

    public boolean containsValue(Object value) {
        return false;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public V get(Object key) {
        int hash = getHash((K) key, capacity);

        if (entities[hash] == null)
            return null;

        return entities[hash].get((K) key);
    }

    public V put(K key, V value) {
        int hash = getHash((K) key, capacity);

        //System.out.println("Hash = " + hash);


        Entity<K, V> e = entities[hash];

        if (e == null) {
            entities[hash] = e = new Entity<K, V>(hash);

            size++;

            //System.out.println("e == null");
            return e.add(key, value);

            //return value;
        } else if (e.size() >= treshold) {

            rehash();

            //System.out.println("e.size > treshold");
            return put(key, value);

            //return value;
        } else {

            //System.out.println("else");

            int prevSize = e.size();

            e.add(key, value);

            int nextSize = e.size();

            if(prevSize != nextSize){
                size++;
            }

            return value;
        }
    }

    public V remove(Object key) {
        int hash = getHash((K)key, capacity);

        Entity<K,V> e = entities[hash];

        if(e == null)
            return null;

        V val = e.remove((K)key);

        if(val != null)
            size--;

        return val;
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void clear() {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public Set<K> keySet() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public Collection<V> values() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public Set<Entry<K, V>> entrySet() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    private void rehash(){
        Entity<K, V>[] tents = entities;
        ListItem<K,V> items[];

        int oldCapacity = capacity;

        size = 0;
        capacity *= 2;
        entities = new Entity[capacity];

        //initAllEntities();

        for(int i = 0; i < oldCapacity; i++){

            if(tents[i] == null)
                continue;

            items = tents[i].getAll();

            for(int j = 0; j < items.length; j++){
                put(items[j].getKey(), items[j].getValue());
            }
        }
    }

    private void initAllEntities(){
        for(int i = 0; i < capacity; i++)
            entities[i] = new Entity<K, V>(i);
    }

}
